home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / editors / mjovesrc.zoo / keymaps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-04  |  11.7 KB  |  610 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "list.h"
  10. #include "fp.h"
  11. #include "termcap.h"
  12. #include "chars.h"
  13. #include "disp.h"
  14. #include "re.h"
  15.  
  16. /* Up until now a keymap was an array of pointers to
  17.    data_obj's.  A data_obj was either a pointer to a built-in
  18.    command or a keyboard macro.  Now a data_obj can be a
  19.    pointer to a keymap as well, which is how prefix keys will
  20.    be handled.
  21.  
  22.    There will be a way to build keymaps and give them names,
  23.    and to look those keymaps up by name, attach them to keys.
  24.    There will be a way to specify a string of key strokes and
  25.    have a series of keymaps built automatically for those
  26.    sequences. */
  27.  
  28. private    void
  29.     fb_aux proto((data_obj *, struct keymap *, char *, char *, size_t));
  30.  
  31. private List    *keymaps;        /* list of all keymaps */
  32. private struct keymap    *mainmap;
  33. #ifdef    IPROCS
  34. private struct keymap    *procsmap;
  35. #endif
  36.  
  37. /* make a new keymap, give it name NAME, initialize the keys array
  38.    to keys, if nonzero, or make an empty one, otherwise */
  39.  
  40. private struct keymap *
  41. km_new(name, keys)
  42. char    *name;
  43. data_obj    **keys;
  44. {
  45.     struct keymap    *km;
  46.  
  47.     km = (struct keymap *) emalloc(sizeof *km);
  48.     (void) list_push(&keymaps, (UnivPtr) km);
  49.     km->Type = KEYMAP;
  50.     km->Name = name;
  51.     if (keys != NULL) {
  52.         km->k_keys = keys;
  53.         km->k_alloc_p = NO;
  54.     } else {
  55.         km->k_keys = (data_obj **) emalloc(NCHARS * sizeof (data_obj *));
  56.         byte_zero((UnivPtr) km->k_keys, NCHARS * sizeof (data_obj *));
  57.         km->k_alloc_p = YES;
  58.     }
  59.     return km;
  60. }
  61.  
  62. #ifdef    NEVER
  63.  
  64. /* free up a keymap */
  65.  
  66. private void
  67. km_destroy(km)
  68. struct keymap    *km;
  69. {
  70.     if (km->k_alloc_p == YES)
  71.         free((char *) km->k_keys);
  72.     km->k_keys = NULL;
  73.     free((char *) km);
  74. }
  75.  
  76. /* lookup a keymap by name */
  77.  
  78. private struct keymap *
  79. km_lookup(name)
  80. char    *name;
  81. {
  82.     List    *lp;
  83.  
  84.     for (lp = keymaps; lp != NULL; lp = list_next(lp))
  85.         if (strcmp(name, ((struct keymap *) list_data(lp))->Name) == 0)
  86.             break;
  87.     if (lp == NULL)
  88.         return NULL;
  89.     return (struct keymap *) list_data(lp);
  90. }
  91.  
  92. #endif
  93.  
  94. /* given a map and a key, return the object bound to that key */
  95.  
  96. #ifdef MiNT
  97. #define km_getkey(m, c)    ((m)->k_keys[(c) & 0377])
  98. #else
  99. #define km_getkey(m, c)    ((m)->k_keys[(c) & CHARMASK])
  100. #endif /* MiNT */
  101.  
  102. #ifndef    km_getkey
  103. data_obj *
  104. km_getkey(m, c)
  105. struct keymap    *m;
  106. int    c;
  107. {
  108.     return (m->k_keys[c & CHARMASK]);
  109. }
  110. #endif
  111.  
  112. private void
  113. km_setkey(m, c, d)
  114. struct keymap    *m;
  115. int    c;
  116. data_obj    *d;
  117. {
  118. #ifdef MiNT
  119.     m->k_keys[c & 0377] = d;
  120. #else
  121.     m->k_keys[c & CHARMASK] = d;
  122. #endif /* MiNT */
  123. }
  124.  
  125. /* get the currently active keymaps into km_buf */
  126.  
  127. private int
  128. get_keymaps(km_buf)
  129. struct keymap    **km_buf;
  130. {
  131.     int    nmaps = 0;
  132.  
  133. #ifdef    IPROCS
  134.     if (curbuf->b_process != NULL)
  135.         km_buf[nmaps++] = procsmap;
  136. #endif
  137.     if (curbuf->b_map != NULL)
  138.         km_buf[nmaps++] = curbuf->b_map;
  139.     km_buf[nmaps++] = mainmap;
  140.  
  141.     return nmaps;
  142. }
  143.  
  144. private struct keymap *
  145. IsPrefix(cp)
  146. data_obj    *cp;
  147. {
  148.     if (cp == NULL || (cp->Type & TYPEMASK) != KEYMAP)
  149.         return NULL;
  150.     return (struct keymap *) cp;
  151. }
  152.  
  153. /* Is `c' a prefix character */
  154.  
  155. int
  156. PrefChar(c)
  157. int    c;
  158. {
  159.     return (int) IsPrefix(km_getkey(mainmap, c));
  160. }
  161.  
  162. void
  163. UnbindC()
  164. {
  165.     char    *keys;
  166.     struct keymap    *map = mainmap;
  167.  
  168.     keys = ask((char *)NULL, ProcFmt);
  169.     for (;;) {
  170.         if (keys[1] == '\0')
  171.             break;
  172.         if ((map = IsPrefix(km_getkey(map, *keys))) == NULL)
  173.             break;
  174.         keys += 1;
  175.     }
  176.     if (keys[1] != '\0')
  177.         complain("That's not a legitimate key sequence.");
  178.     km_setkey(map, keys[0], (data_obj *)NULL);
  179. }
  180.  
  181. private void
  182. BindWMap(map, lastkey, cmd)
  183. struct keymap    *map;
  184. int    lastkey;
  185. data_obj     *cmd;
  186. {
  187.     struct keymap    *nextmap;
  188.     int    c;
  189.  
  190.     c = addgetc();
  191.     if (c == EOF) {
  192.         if (lastkey == EOF)
  193.             complain("[Empty key sequence]");
  194.         complain("[Premature end of key sequence]");
  195.     } else {
  196.         if ((nextmap = IsPrefix(km_getkey(map, c))) != NULL)
  197.             BindWMap(nextmap, c, cmd);
  198.         else {
  199.             km_setkey(map, c, cmd);
  200. #ifdef    MAC
  201.             ((struct cmd *) cmd)->c_key = c;    /* see about_j() in mac.c */
  202.             if (map->k_keys == MainKeys)
  203.                 ((struct cmd *) cmd)->c_map = F_MAINMAP;
  204.             else if (map->k_keys == EscKeys)
  205.                 ((struct cmd *) cmd)->c_map = F_PREF1MAP;
  206.             else if (map == (struct keymap *) CtlxKeys)
  207.                 ((struct cmd *) cmd)->c_map = F_PREF2MAP;
  208. #endif
  209.         }
  210.     }
  211. }
  212.  
  213. private void
  214. BindSomething(proc, map)
  215. data_obj    *(*proc) ptrproto((const char *));
  216. struct keymap    *map;
  217. {
  218.     data_obj    *d;
  219.  
  220.     if ((d = (*proc)(ProcFmt)) == NULL)
  221.         return;
  222.     s_mess(": %f %s ", d->Name);
  223.     BindWMap(map, EOF, d);
  224. }
  225.  
  226. void
  227. BindAKey()
  228. {
  229.     BindSomething(findcom, mainmap);
  230. }
  231.  
  232. void
  233. BindMac()
  234. {
  235.     BindSomething(findmac, mainmap);
  236. }
  237.  
  238. private void
  239. DescWMap(map, key)
  240. struct keymap    *map;
  241. int    key;
  242. {
  243.     data_obj    *cp = km_getkey(map, key);
  244.     struct keymap    *prefp;
  245.  
  246.     if (cp == NULL)
  247.         add_mess("is unbound.");
  248.     else if ((prefp = IsPrefix(cp)) != NULL)
  249.         DescWMap(prefp, addgetc());
  250.     else
  251.         add_mess("is bound to %s.", cp->Name);
  252. }
  253.  
  254. void
  255. KeyDesc()
  256. {
  257.     s_mess(ProcFmt);
  258.     DescWMap(mainmap, addgetc());
  259. }
  260.  
  261. private void
  262. DescMap(map, pref)
  263. struct keymap    *map;
  264. char    *pref;
  265. {
  266.     int    c1,
  267.         c2;
  268.     char    keydescbuf[40];
  269.     struct keymap    *prefp;
  270.  
  271.     for (c1 = 0; c1 < NCHARS; c1 = c2 + 1) {
  272.         c2 = c1;
  273.         if (km_getkey(map, c1) == 0)
  274.             continue;
  275.         do ; while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2));
  276.         c2 -= 1;
  277.         swritef(keydescbuf, sizeof(keydescbuf),
  278.             c1==c2? "%s %p" : c1==c2+1? "%s {%p,%p}" : "%s [%p-%p]",
  279.             pref, c1, c2);
  280.         if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map))
  281.             DescMap(prefp, keydescbuf);
  282.         else
  283.             Typeout("%-18s%s", keydescbuf, km_getkey(map, c1)->Name);
  284.     }
  285. }
  286.  
  287. void
  288. DescBindings()
  289. {
  290.     TOstart("Key Bindings", TRUE);
  291.     DescMap(mainmap, NullStr);
  292.     TOstop();
  293. }
  294.  
  295. private void
  296. find_binds(dp, buf, size)
  297. data_obj    *dp;
  298. char    *buf;
  299. size_t    size;
  300. {
  301.     char    *endp;
  302.  
  303.     buf[0] = '\0';
  304.     fb_aux(dp, mainmap, (char *) NULL, buf, size);
  305.     endp = buf + strlen(buf) - 2;
  306.     if ((endp > buf) && (strcmp(endp, ", ") == 0))
  307.         *endp = '\0';
  308. }
  309.  
  310. private void
  311. fb_aux(cp, map, prefix, buf, size)
  312. register data_obj    *cp;
  313. struct keymap    *map;
  314. char    *prefix,
  315.     *buf;
  316. size_t    size;
  317. {
  318.     int    c1,
  319.         c2;
  320.     char    *bufp = buf + strlen(buf),
  321.         prefbuf[20];
  322.     struct keymap    *prefp;
  323.  
  324.     for (c1 = 0; c1 < NCHARS; c1 = c2 + 1) {
  325.         c2 = c1;
  326.         if (km_getkey(map, c1) == cp) {
  327.             do ; while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2));
  328.             c2 -= 1;
  329.             if (prefix)
  330.                 swritef(bufp, sizeof(buf) - (bufp-buf), "%s ",
  331.                     prefix);
  332.             bufp += strlen(bufp);
  333.             swritef(bufp, size - (bufp-buf),
  334.                 c1==c2? "%p" : c1==c2+1? "{%p,%p}" : "[%p-%p]",
  335.                 c1, c2);
  336.         }
  337.         if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map))  {
  338.             swritef(prefbuf, sizeof(prefbuf), "%p", c1);
  339.             fb_aux(cp, prefp, prefbuf, bufp, size-(bufp-buf));
  340.         }
  341.         bufp += strlen(bufp);
  342.     }
  343. }
  344.  
  345. void
  346. DescCom()
  347. {
  348.     data_obj    *dp;
  349.     char    pattern[100],
  350.         *file = CmdDb;
  351.     const char    *doc_type;
  352.     static const char var_type[] = "Variable";
  353.     static const char cmd_type[] = "Command";
  354.     File    *fp;
  355.  
  356.     if (!strcmp(LastCmd->Name, "describe-variable")) {
  357.         doc_type = var_type;
  358.         dp = (data_obj *) findvar(ProcFmt);
  359.     } else {
  360.         doc_type = cmd_type;
  361.         dp = (data_obj *) findcom(ProcFmt);
  362.     }
  363.     if (dp == NULL)
  364.         return;
  365.     fp = open_file(file, iobuff, F_READ, YES, YES);
  366.     Placur(ILI, 0);
  367.     flushscreen();
  368.     swritef(pattern, sizeof(pattern), "^:entry \"%s\" \"%s\"$",
  369.         dp->Name, doc_type);
  370.     TOstart("Help", TRUE);
  371.     for (;;) {
  372.         if (f_gets(fp, genbuf, (size_t)LBSIZE)) {
  373.             Typeout("There is no documentation for \"%s\".", dp->Name);
  374.             break;
  375.         }
  376.         if (genbuf[0] == ':' && LookingAt(pattern, genbuf, 0)) {
  377.             /* found it ... let's print it */
  378.             if (doc_type == var_type)
  379.                 Typeout(dp->Name);
  380.             else if (doc_type == cmd_type) {
  381.                 char    binding[128];
  382.  
  383.                 find_binds(dp, binding, sizeof(binding));
  384.                 if (blnkp(binding))
  385.                     Typeout("To invoke %s, type \"ESC X %s<cr>\".",
  386.                         dp->Name, dp->Name);
  387.                 else
  388.                     Typeout("Type \"%s\" to invoke %s.",
  389.                         binding, dp->Name);
  390.             }
  391.             Typeout("");
  392.             while (!f_gets(fp, genbuf, (size_t)LBSIZE)
  393.             && strncmp(genbuf, ":entry", (size_t)6) != 0) {
  394.                 Typeout("%s", genbuf);
  395.             }
  396.             break;
  397.         }
  398.     }
  399.     f_close(fp);
  400.     TOstop();
  401. }
  402.  
  403.  
  404. void
  405. Apropos()
  406. {
  407.     register const struct cmd    *cp;
  408.     register struct macro    *m;
  409.     register const struct variable    *v;
  410.     char    *ans;
  411.     bool    anyfs = NO,
  412.         anyvs = NO,
  413.         anyms = NO;
  414.     char    buf[256];
  415.  
  416.     ans = ask((char *)NULL, ": %f (keyword) ");
  417.     TOstart("Help", TRUE);
  418.     for (cp = commands; cp->Name != NULL; cp++)
  419.         if (sindex(ans, cp->Name)) {
  420.             if (!anyfs) {
  421.                 Typeout("Commands");
  422.                 Typeout("--------");
  423.             }
  424.             find_binds((data_obj *) cp, buf, sizeof(buf));
  425.             if (buf[0])
  426.                 Typeout(": %-35s (%s)", cp->Name, buf);
  427.             else
  428.                 Typeout(": %s", cp->Name);
  429.             anyfs = YES;
  430.         }
  431.     if (anyfs)
  432.         Typeout(NullStr);
  433.     for (v = variables; v->Name != NULL; v++)
  434.         if (sindex(ans, v->Name)) {
  435.             if (!anyvs) {
  436.                 Typeout("Variables");
  437.                 Typeout("---------");
  438.             }
  439.             anyvs = YES;
  440.             vpr_aux(v, buf, sizeof(buf));
  441.             Typeout(": set %-26s %s", v->Name, buf);
  442.         }
  443.     if (anyvs)
  444.         Typeout(NullStr);
  445.     for (m = macros; m != NULL; m = m->m_nextm)
  446.         if (sindex(ans, m->Name)) {
  447.             if (!anyms) {
  448.                 Typeout("Macros");
  449.                 Typeout("------");
  450.             }
  451.             anyms = YES;
  452.             find_binds((data_obj *) m, buf, sizeof(buf));
  453.             if (buf[0])
  454.                 Typeout(": %-35s (%s)", m->Name, buf);
  455.             else
  456.                 Typeout(": %-35s %s", "execute-macro", m->Name);
  457.         }
  458.     TOstop();
  459. }
  460.  
  461. #ifdef    NEVER
  462. private char *
  463. km_newname()
  464. {
  465.     char    buffer[128];
  466.     static int    km_count = 1;
  467.  
  468.     swritef(buffer, sizeof(buffer), "keymap-%d", km_count++);
  469.     return copystr(buffer);
  470. }
  471. #endif
  472.  
  473. void
  474. InitKeymaps()
  475. {
  476.     struct keymap    *km;
  477.  
  478.     mainmap = km_new(copystr("mainmap"), MainKeys);
  479.  
  480.     /* setup ESC map */
  481.     km = km_new(copystr("ESC-map"), EscKeys);
  482.     km_setkey(mainmap, ESC, (data_obj *) km);
  483.  
  484.     /* setup Ctlx map */
  485.     km = km_new(copystr("CTLX-map"), CtlxKeys);
  486.     km_setkey(mainmap, CTL('X'), (data_obj *) km);
  487. }
  488.  
  489. void
  490. MakeKMap()
  491. {
  492.     char    *name;
  493.  
  494.     name = ask((char *)NULL, ProcFmt);
  495.     (void) km_new(copystr(name), (data_obj **)NULL);
  496. }
  497.  
  498. private data_obj *
  499. findmap(fmt)
  500. const char    *fmt;
  501. {
  502.     List    *lp;
  503.     char    *strings[128];
  504.     int    i;
  505.  
  506.     for (lp = keymaps, i = 0; lp != NULL; lp = list_next(lp))
  507.         strings[i++] = ((struct keymap *) list_data(lp))->Name;
  508.     strings[i] = NULL;
  509.  
  510.     i = complete(strings, fmt, 0);
  511.     if (i < 0)
  512.         return NULL;
  513.     lp = keymaps;
  514.     while (--i >= 0)
  515.         lp = list_next(lp);
  516.     return (data_obj *) list_data(lp);
  517. }
  518.  
  519. #ifdef    IPROCS
  520. private void
  521. mk_proc_km()
  522. {
  523.     procsmap = km_new("process-keymap", (data_obj **)NULL);
  524. }
  525.  
  526. void
  527. ProcBind()
  528. {
  529.     data_obj    *d;
  530.  
  531.     if (procsmap == NULL)
  532.         mk_proc_km();
  533.  
  534.     if ((d = findcom(ProcFmt)) == NULL)
  535.         return;
  536.     s_mess(": %f %s ", d->Name);
  537.     BindWMap(procsmap, EOF, d);
  538. }
  539.  
  540. void
  541. ProcKmBind()
  542. {
  543.     data_obj    *d;
  544.  
  545.     if (procsmap == NULL)
  546.         mk_proc_km();
  547.     if ((d = findmap(ProcFmt)) == NULL)
  548.         return;
  549.     s_mess(": %f %s ", d->Name);
  550.     BindWMap(procsmap, EOF, d);
  551. }
  552.  
  553. #endif
  554.  
  555. void
  556. KmBind()
  557. {
  558.     BindSomething(findmap, mainmap);
  559. }
  560.  
  561. void
  562. dispatch(c)
  563. register int    c;
  564. {
  565.     data_obj    *cp;
  566.     struct keymap    *maps[10];    /* never more than 10 active
  567.                        maps at a time, I promise */
  568.     int    nmaps;
  569.  
  570.     this_cmd = 0;
  571.     nmaps = get_keymaps(maps);
  572.  
  573.     for (;;) {
  574.         int    i,
  575.             nvalid,
  576.             slow = NO;
  577.  
  578.         for (i = 0, nvalid = 0; i < nmaps; i++) {
  579.             if (maps[i] == NULL)
  580.                 continue;
  581.             cp = km_getkey(maps[i], c);
  582.             if (cp != NULL) {
  583.                 if (obj_type(cp) != KEYMAP) {
  584.                     ExecCmd(cp);
  585.                     return;
  586.                 }
  587.                 nvalid += 1;
  588.             }
  589.             maps[i] = (struct keymap *) cp;
  590.         }
  591.         if (nvalid == 0) {
  592.             char    strokes[128];
  593.  
  594.             pp_key_strokes(strokes, sizeof (strokes));
  595.             s_mess("[%sunbound]", strokes);
  596.             rbell();
  597.             clr_arg_value();
  598.             errormsg = NO;
  599.             return;
  600.         }
  601.  
  602.         c = waitchar(&slow);
  603.         if (c == AbortChar) {
  604.             message("[Aborted]");
  605.             rbell();
  606.             return;
  607.         }
  608.     }
  609. }
  610.